package com.youlian.cloud.core.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.io.InputStream;

/**
 * http调用工具
 *
 * @author Liukx
 * @create 2018-04-26 14:45
 * @email liukx@elab-plus.com
 **/
@Slf4j
public class RestTemplateUtils {


    public RestTemplate restTemplate;

    private HttpHeaders headers;

    private RestTemplate getRestTemplate() {
        return restTemplate;
    }

    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public HttpHeaders getHeaders() {
        return headers;
    }

    public void setHeaders(HttpHeaders headers) {
        this.headers = headers;
    }

    public RestTemplateUtils() {
        //复杂构造函数的使用
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        // 设置超时
        requestFactory.setConnectTimeout(1000);
        // 读取超时
        requestFactory.setReadTimeout(5000);

        //利用复杂构造器可以实现超时设置，内部实际实现为 HttpClient
        restTemplate = new RestTemplate(requestFactory);

        //设置HTTP请求头信息，实现编码等
        headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
    }

    /**
     * post数据放送
     *
     * @param url
     * @param reqParam
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T post(String url, Object reqParam, Class<T> clazz) {
        return post(url, headers, reqParam, clazz);
    }

    /**
     * 执行post请求
     *
     * @param url         url
     * @param httpHeaders head参数
     * @param reqParam    请求参数
     * @param clazz       类
     * @param <T>
     * @return
     */
    public <T> T post(String url, HttpHeaders httpHeaders, Object reqParam, Class<T> clazz) {
        String newUrl = getUrl(url);
        Transaction t = Cat.getProducer().newTransaction("third_party_url", newUrl);
        log.info(" URL : " + url);
        if (reqParam != null) {
            log.info(" RequestData : " + StringUtils.logOut(logData(reqParam)));
        }
        T responseData = null;
        try {
            //利用容器实现数据封装，发送
            HttpEntity<Object> entity = new HttpEntity<Object>(reqParam, httpHeaders);
            responseData = restTemplate.postForObject(url, entity, clazz);
            t.setStatus(Transaction.SUCCESS);
            logResponse(responseData);
        } catch (Exception e) {
            log.error("------ 第三方接口调用失败 : ", e);
            t.setStatus(e.getClass().getSimpleName());
        } finally {
            t.complete();
        }
        return responseData;
    }

    /**
     * 通用的返回日志
     *
     * @param responseData
     * @param <T>
     */
    private <T> void logResponse(T responseData) {
        if (dontCareType(responseData)) {
            log.info(" 不关心的类型 ... ");
        } else {
            log.info(" ResponseData : " + StringUtils.logOut(logData(responseData)));
        }
    }

    /**
     * get请求发送
     *
     * @param url
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T get(String url, Class<T> clazz) {
        String newUrl = getUrl(url);
        Transaction t = Cat.getProducer().newTransaction("third_party_url", newUrl);
        log.info(" URL : " + url);
        //利用容器实现数据封装，发送
        T responseData = null;
        try {
            responseData = restTemplate.getForObject(url, clazz);
            t.setStatus(Transaction.SUCCESS);
            if (responseData != null) {
                logResponse((T) responseData);
            }
        } catch (Exception e) {
            log.error("------ 第三方接口调用失败 : ", e);
            t.setStatus(e.getClass().getSimpleName());
        } finally {
            t.complete();
        }
        return responseData;
    }

    private <T> boolean dontCareType(T responseData) {
        return responseData instanceof byte[] || responseData instanceof InputStream;
    }

    /**
     * 文件上传接口
     *
     * @param url
     * @param reqParam
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T postUpload(String url, Object reqParam, Class<T> clazz) {
        log.info(" URL : " + url);
        log.info(" RequestData : " + ObjectUtils.objectParseJsonStr(reqParam));

        String newUrl = getUrl(url);
        Transaction t = Cat.getProducer().newTransaction("third_party_url", newUrl);
        T responseData = null;
        try {
            //利用容器实现数据封装，发送
            HttpEntity<Object> entity = new HttpEntity<Object>(reqParam, new HttpHeaders());
            ResponseEntity<T> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, clazz);
            responseData = exchange.getBody();
            if (exchange != null && responseData != null) {
                log.info(" ResponseData : " + StringUtils.logOut(logData(responseData)));
            }
            t.setStatus(Transaction.SUCCESS);
        } catch (Exception e) {
            log.error("------ 第三方接口调用失败 : ", e);
            t.setStatus(e.getClass().getSimpleName());
        } finally {
            t.complete();
        }
        return responseData;
    }

    /**
     * 获取除开?号后面的URL
     *
     * @param url
     * @return
     */
    private String getUrl(String url) {
        if (ObjectUtils.isNotEmpty(url)) {
            String newUrl = url;
            if (url.indexOf("?") > 0) {
                newUrl = url.substring(0, url.indexOf("?"));
            }
            return newUrl;
        }
        return url;
    }

    private String logData(Object data) {
        if (data == null) {
            return "";
        }

        if (data instanceof String) {
            return data.toString();
        }
        String logData = "";
        try {
            logData = ObjectUtils.objectParseJsonStr(data);
        } catch (Exception e) {
            return data.toString();
        }
        return logData;
    }

    public static void main(String[] args) {
        String param = "{\n" +
                "\t\"pageno\":\"1\",\n" +
                "\t\"pagesize\":\"10\",\n" +
                "\t\"houseid\":\"102\",\n" +
                "\t\"time\":\"2017-04-13\"\n" +
                "}";
        JSONObject jsonObject = JSON.parseObject(param);
        RestTemplateUtils restTemplateUtils = new RestTemplateUtils();
//        JSONModel post = restTemplateUtils.post("http://localhost:9005/skyforest/dd/pageList", jsonObject, JSONModel.class);
//        System.out.println(JSON.toJSONString(post));
    }

}
